﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Entity;
using eShop.Model;
using ECommerce.Library.DataStructure;
using System.Text;
using log4net;
using ECommerce.Library;
using AutoGear.BLL;
using eShop.DataAccess;

namespace eShop.Business
{
    public class CategoryManager
    {
        public static void Delete(int categoryId)
        {
            /**************************************************
             * will update database table, will delete physical
             * files and will write in admin log about the 
             * delete
             **************************************************/
            CategoryDAO.DeleteTblProductCategory(categoryId);
        }

        public static void Update(Category category)
        {
            /**************************************************
             * will update database table, will update physical
             * files 
             **************************************************/
            if (category.CategoryNameChanged)
            {
                category.CategoryUrl = CategoryFileAccessUtility.UpdateCategoryFiles(category.CategoryUrl, category);
            }

            CategoryDAO.Save(category);
        }

        public static ReadWriteCustomCollection<Category> GetSubCategories(Category rootCategory)
        {
            /**************************************************
             * check whether root category is null or not, if 
             * not null than load child categories form DAL
             * and bind the info and return the subcategories
             **************************************************/

            try
            {
                ReadWriteCustomCollection<Category> subCategories = new ReadWriteCustomCollection<Category>();

                if (rootCategory == null)
                    return subCategories;

                ECommerce.DAL.CustomCollection<Category> tblProductcategories = CategoryDAO.GetActiveSubCategoriesByParentCategory(rootCategory.CategoryId);
                if (tblProductcategories != null)
                {
                    for (int i = 0; i < tblProductcategories.Count; i++)
                    {
                        subCategories.Add(tblProductcategories[i]);
                    }
                }
                return subCategories;
            }
            catch (Exception ex)
            {

                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("GetSubCategories caused server error: Parameters( ");
                logText = logText.Append("rootCategory -> ").Append(rootCategory.ToString());
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ProductCategory");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);
                throw ex;

            }
        }


        public static ReadWriteCustomCollection<Product> GetSubProducts(int ParentCategoryId)
        {
            ReadWriteCustomCollection<Product> productTree = new ReadWriteCustomCollection<Product>();
            Category parentCategory = GetById(ParentCategoryId);
            ReadWriteCustomCollection<Category> subCategories = GetSubCategories(parentCategory);
            if (subCategories.Count > 0)
            {
                foreach (Category productCategory in subCategories)
                {
                    ReadWriteCustomCollection<Product> tmpTree = GetSubProducts(productCategory.CategoryId);
                    foreach (Product product in tmpTree)
                    {
                        productTree.Add(product);
                    }
                }
            }
            else
            {
                ReadWriteCustomCollection<Product> tmpTree = Product.ProductByCategory(ParentCategoryId, string.Empty, 1, 99999, DataState.NonDeleted);
                return tmpTree;
            }
            return productTree;
        }

        public static ReadWriteCustomCollection<Category> GetActiveSubCategoriesPaged(int categoryId, string orderBy, int startRow, int pageSize)
        {
            ReadWriteCustomCollection<Category> subCategories = new ReadWriteCustomCollection<Category>();

            ECommerce.DAL.CustomCollection<Category> tblProductcategories = CategoryDAO.GetActiveSubCategoriesByParentCategoryIdPaged(categoryId, orderBy, startRow, pageSize);
            if (tblProductcategories != null)
            {
                for (int i = 0; i < tblProductcategories.Count; i++)
                {
                    subCategories.Add(tblProductcategories[i]);
                }
            }
            return subCategories;
        }

        public static ReadWriteCustomCollection<Category> Categories(int howMany)
        {
            /**************************************************
             * Reads from DAL a list of category information
             * and binds them in Product category object and
             * returns a perticular number of items refered
             * in howMany required.
             **************************************************/
            try
            {
                ReadWriteCustomCollection<Category> productCategory = new ReadWriteCustomCollection<Category>();
                ECommerce.DAL.CustomCollection<Category> tblProductcategories = CategoryDAO.GetActiveCategoriesByCount(howMany);
                if (tblProductcategories != null)
                {
                    for (int i = 0; i < tblProductcategories.Count; i++)
                    {
                        productCategory.Add(tblProductcategories[i]);
                    }
                }
                return productCategory;
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Categories caused server error: Parameters( ");
                logText = logText.Append("howMany -> ").Append(howMany);
                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ProductCategory");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);
                // return failure
                throw ex;
            }
        }

        public static Category Create(string categoryName, string categoryTitle, string categoryDescription,
            string logoTemporaryFilePath, string displayOrder, bool isActive, bool isFeatured, int parentCategoryId, string productDisplayOrder, string categoryBannerTemporaryFilePath)
        {
            try
            {
                int newCategoryId = 0;

                categoryName = Security.BindStringInput(categoryName, SecurityLevel.Zero);
                categoryTitle = Security.BindStringInput(categoryTitle, SecurityLevel.Zero);
                categoryDescription = Security.BindStringInput(categoryDescription, SecurityLevel.Zero);
                logoTemporaryFilePath = Security.BindStringInput(logoTemporaryFilePath, SecurityLevel.Zero);

                // counting how many category has same name
                int count = CategoryDAO.GetProductCategoryCountByNameAndParent(parentCategoryId,
                    categoryName);
                // If no other category has the same name, 
                // we create it.
                if (count <= 0)
                {
                    newCategoryId = CategoryDAO.CreateNewTblProductCategory(categoryName, categoryTitle, categoryDescription, string.Empty,
                        string.Empty, displayOrder, isFeatured, isActive, false, DateTime.Now, 0, 0, parentCategoryId, productDisplayOrder, string.Empty);

                    Category newCategory = CategoryDAO.GetTblProductCategoryByCategoryId(newCategoryId);

                    newCategory = CategoryFileAccessUtility.CreateCategoryFiles(newCategory, logoTemporaryFilePath, categoryBannerTemporaryFilePath);

                    newCategory.CategoryUrl = newCategory.CategoryUrl;
                    newCategory.CategoryImageUrl = newCategory.CategoryImageUrl;
                    newCategory.CategoryBannerImageUrl = newCategory.CategoryBannerImageUrl;

                    CategoryDAO.UpdateTblProductCategory(newCategory);
                    CategoryDAO.IncreaseSubCategoryCount(parentCategoryId);
                    return newCategory;
                }
                else
                    throw new InvalidOperationException("There is already a category with same name");
            }
            catch (Exception ex)
            {
                // Setting log information about the exception
                StringBuilder logText = new StringBuilder("Create caused server error: Parameters( ");
                logText = logText.Append("categoryName -> ").Append(categoryName);
                logText = logText.Append("categoryDescription -> ").Append(categoryDescription);
                logText = logText.Append("logoTemporaryFilePath -> ").Append(logoTemporaryFilePath);
                logText = logText.Append("isActive -> ").Append(isActive.ToString());
                logText = logText.Append("isFeatured -> ").Append(isFeatured.ToString());
                logText = logText.Append("displayOrder -> ").Append(displayOrder);
                logText = logText.Append("parentCategoryId -> ").Append(parentCategoryId.ToString());

                logText = logText.Append(" )");

                // Write the log into handled exception list
                ILog log = LogHelper.GetHandledFileLogger("ProductCategory");
                if (log.IsErrorEnabled)
                    log.Error(logText.ToString(), ex);

                throw ex;
            }
        }

        public static ReadWriteCustomCollection<Category> FilterCategory(FilterType filterType)
        {
            ECommerce.DAL.CustomCollection<Category> categoryData = null;

            if (filterType == FilterType.All)
                categoryData = CategoryDAO.GetActiveCategoriesByCount(1000);
            else
                categoryData = CategoryDAO.GetProductCategoryByPrefix(filterType.ToString());

            ReadWriteCustomCollection<Category> categories = LoadFromCustomCollection(categoryData);

            return categories;
        }

        public static ReadWriteCustomCollection<Category> LoadFromCustomCollection(ECommerce.DAL.CustomCollection<Category> categoryData)
        {
            ReadWriteCustomCollection<Category> result = new ReadWriteCustomCollection<Category>();

            for (int i = 0; i < categoryData.Count; i++)
            {
                result.Add(categoryData[i]);
            }

            return result;
        }

        public static ReadWriteCustomCollection<KeyValuePair<string, string>> GetSubCategoryTree(int ParentCategoryId)
        {
            ReadWriteCustomCollection<KeyValuePair<string, string>> productCategoryTree = new ReadWriteCustomCollection<KeyValuePair<string, string>>();
            try
            {

                Category parentCategory = GetById(ParentCategoryId);
                ReadWriteCustomCollection<Category> subCategories = GetSubCategories(parentCategory);
                productCategoryTree.Add(new KeyValuePair<string, string>(parentCategory.CategoryName, parentCategory.CategoryId.ToString()));
                if (subCategories.Count > 0)
                {
                    foreach (Category productCategory in subCategories)
                    {
                        ReadWriteCustomCollection<KeyValuePair<string, string>> tmpTree = GetSubCategoryTree(productCategory.CategoryId);
                        foreach (KeyValuePair<string, string> childCategory in tmpTree)
                        {
                            productCategoryTree.Add(new KeyValuePair<string, string>("--" + childCategory.Key, childCategory.Value));
                        }
                    }
                }
            }
            catch (Exception) { }
            return productCategoryTree;
        }


        public static ReadWriteCustomCollection<KeyValuePair<string, string>> GetSubCategorySiteMapTree(int ParentCategoryId, int ChildCategoryId)
        {
            ReadWriteCustomCollection<KeyValuePair<string, string>> productCategoryTree = new ReadWriteCustomCollection<KeyValuePair<string, string>>();
            Category parentCategory = GetById(ParentCategoryId);
            ReadWriteCustomCollection<Category> subCategories = GetSubCategories(parentCategory);
            if (parentCategory.CategoryId == ChildCategoryId)
            {
                productCategoryTree.Add(new KeyValuePair<string, string>(parentCategory.CategoryName, parentCategory.CategoryUrl));
            }
            if (subCategories.Count > 0 && parentCategory.CategoryId != ChildCategoryId)
            {
                foreach (Category productCategory in subCategories)
                {
                    ReadWriteCustomCollection<KeyValuePair<string, string>> tmpTree = GetSubCategorySiteMapTree(productCategory.CategoryId, ChildCategoryId);
                    int count = tmpTree.Count;
                    if (count > 0)
                    {
                        productCategoryTree.Add(new KeyValuePair<string, string>(parentCategory.CategoryName, parentCategory.CategoryUrl));
                    }
                    foreach (KeyValuePair<string, string> childCategory in tmpTree)
                    {
                        productCategoryTree.Add(new KeyValuePair<string, string>(childCategory.Key, childCategory.Value));
                    }
                    if (count > 0)
                    {
                        return productCategoryTree;
                    }
                }
            }

            return productCategoryTree;
        }

        public static void DeleteCategory(Category oldCategory, bool IsDeleteSubProducts)
        {
            /**************************************************
             * will update database table, will delete physical
             * files and will write in admin log about the 
             * delete
             **************************************************/
            if (IsDeleteSubProducts)
            {
                Product.DeleteProducts(CategoryManager.GetSubProducts(oldCategory.CategoryId));
                if (CategoryFileAccessUtility.DeleteCategoryFiles(oldCategory))
                {
                    CategoryDAO.DecreaseSubCategoryCount(oldCategory.ParentCategory.CategoryId);
                    CategoryManager.Delete(oldCategory.CategoryId);
                    //oldCategory.IsDeleted = true;
                    //oldCategory.Update();
                }
            }
            else
            {

                if (oldCategory.SubCategoryCount > 0 || oldCategory.ProductCount > 0)
                    throw new InvalidOperationException(AutoGearCommonMessage.InvalidCategoryDeleteDueToNonEmpty);
                if (CategoryFileAccessUtility.DeleteCategoryFiles(oldCategory))
                {
                    CategoryDAO.DecreaseSubCategoryCount(oldCategory.ParentCategory.CategoryId);
                    oldCategory.IsDeleted = true;
                    CategoryManager.Update(oldCategory);
                }
            }

        }

        public static Category Load(int categoryId, bool isActiveOnly)
        {
            Category productCategory = CategoryManager.Load(categoryId);
            if (isActiveOnly && productCategory.IsActive)
            {
                return productCategory;
            }
            else
            {
                return null;
            }
        }

        public static Category Load(int categoryId)
        {
            Category category = CategoryManager.GetById(categoryId);
            if (category != null)
            {
                if (!category.IsDeleted)
                    return category;
                else return null;
            }
            else return null;
        }


        public static string ChangeCategoryImage(string logoImageFile, Category category)
        {
            try
            {
                CategoryFileAccessUtility.DeleteCategoryLogo(category.CategoryImageUrl);

                return CategoryFileAccessUtility.UploadCategoryLogo(logoImageFile, category.CategoryName);

            }
            catch { throw new Exception("ChangeCategoryImage Method could not upload image"); }
        }

        public static string ChangeCategoryBannerImage(string logoImageFile, Category category)
        {
            try
            {
                CategoryFileAccessUtility.DeleteCategoryLogo(category.CategoryBannerImageUrl);

                return CategoryFileAccessUtility.UploadCategoryBanner(logoImageFile, category.CategoryName);

            }
            catch { throw new Exception("ChangeCategoryImage Method could not upload image"); }
        }

        public static void DeleteCategories(List<int> idList)
        {
            CategoryDAO.DeleteTblProductCategoryList(idList);
        }

        public static void DeleteCategories(ReadWriteCustomCollection<Category> categories)
        {
            foreach (Category category in categories)
            {
                CategoryManager.DeleteCategory(category, true);
            }
        }

        public static int GetBackendCategoryCount(bool includeDeleted)
        {
            if (includeDeleted)
            {
                return CategoryDAO.GetAllTblProductCategoryPagedCount(string.Empty, 0, 0);
            }
            else
            {
                return CategoryDAO.GetNonDeletedCategoriesCount();
            }
        }

        public static ReadWriteCustomCollection<Category> GetBackendCategoryList(bool includeDeleted, string orderBy, int startIndex, int pageSize)
        {
            if (includeDeleted)
            {
                return LoadFromCustomCollection(CategoryDAO.GetAllTblProductCategoryPaged(orderBy, startIndex, pageSize));
            }
            else
            {
                return LoadFromCustomCollection(CategoryDAO.GetNonDeletedSubCategoriesPaged(orderBy, startIndex, pageSize));
            }
        }

        public static ReadWriteCustomCollection<Category> GetBackendCategoryListByNameSearch(string categoryName, bool includeDeleted, string orderBy, int startIndex, int pageSize)
        {
            if (includeDeleted)
            {
                return LoadFromCustomCollection(CategoryDAO.GetAllCategoriesByNamePaged(categoryName, orderBy, startIndex, pageSize));
            }
            else
            {
                return LoadFromCustomCollection(CategoryDAO.GetNonDeletedCategoriesByNamePaged(categoryName, orderBy, startIndex, pageSize));
            }
        }

        public static int GetBackendCategoryListByNameCount(string categoryName, bool includeDeleted)
        {
            if (includeDeleted)
            {
                return CategoryDAO.GetAllCategoriesByNameCount(categoryName);
            }
            else
            {
                return CategoryDAO.GetNonDeletedCategoriesByNameCount(categoryName);
            }
        }

        public static ReadWriteCustomCollection<Category> GetBackendCategoryListByParentCategoryIdSearch(int parentCategoryId, bool includeDeleted, string orderBy, int startIndex, int pageSize)
        {
            if (includeDeleted)
            {
                return LoadFromCustomCollection(CategoryDAO.GetTblProductCategoryByParentCategoryIdPaged(parentCategoryId, orderBy, startIndex, pageSize));
            }
            else
            {
                return LoadFromCustomCollection(CategoryDAO.GetNonDeletedSubCategoriesByParentCategoryIdPaged(parentCategoryId, orderBy, startIndex, pageSize));
            }
        }

        public static int GetBackendCategoryListByParentCategoryIdCount(int parentCategoryId, bool includeDeleted)
        {
            if (includeDeleted)
            {
                return CategoryDAO.GetTblProductCategoryByParentCategoryIdPagedCount(parentCategoryId, string.Empty, 0, 0);
            }
            else
            {
                return CategoryDAO.GetNonDeletedSubCategoriesByParentCategoryIdCount(parentCategoryId);
            }
        }


        public static ReadWriteCustomCollection<Category> GetBackendCategoryListByParentCategoryIdAndNameSearch(int parentCategoryId, string categoryName, bool includeDeleted, string orderBy, int startIndex, int pageSize)
        {
            if (includeDeleted)
            {
                return LoadFromCustomCollection(CategoryDAO.GetAllCategoriesByParentCategoryIdAndNamePaged(parentCategoryId, categoryName, orderBy, startIndex, pageSize));
            }
            else
            {
                return LoadFromCustomCollection(CategoryDAO.GetNonDeletedCategoriesByParentCategoryIdAndNamePaged(parentCategoryId, categoryName, orderBy, startIndex, pageSize));
            }
        }

        public static int GetBackendCategoryListByParentCategoryIdAndNameCount(int parentCategoryId, string categoryName, bool includeDeleted)
        {
            if (includeDeleted)
            {
                return CategoryDAO.GetAllCategoriesByParentCategoryIdAndNameCount(parentCategoryId, categoryName);
            }
            else
            {
                return CategoryDAO.GetNonDeletedCategoriesByParentCategoryIdAndNameCount(parentCategoryId, categoryName);
            }
        }


        public static List<KeyValuePair<string, string>> GetProductDisplayOrders()
        {
            List<KeyValuePair<string, string>> productDisplayOrders = new List<KeyValuePair<string, string>>();
            productDisplayOrders.Add(new KeyValuePair<string, string>(ProductDisplayOrders.Width.ToString(), ProductDisplayOrders.Width.ToString() + "Value"));
            productDisplayOrders.Add(new KeyValuePair<string, string>(ProductDisplayOrders.Diameter.ToString(), ProductDisplayOrders.Diameter.ToString() + "Value"));
            productDisplayOrders.Add(new KeyValuePair<string, string>(ProductDisplayOrders.Length.ToString(), ProductDisplayOrders.Length.ToString() + "Value"));
            productDisplayOrders.Add(new KeyValuePair<string, string>(ProductDisplayOrders.ThreadCount.ToString(), ProductDisplayOrders.ThreadCount.ToString() + "Value"));
            return productDisplayOrders;
        }


        #region ICloneable Members

        public static object Clone(Category category)
        {
            Category clone = new Category();
            clone.CategoryId = category.CategoryId;
            clone.CategoryImageUrl = category.CategoryImageUrl;
            clone.CategoryName = category.CategoryName;
            clone.CategoryTitle = category.CategoryTitle;
            clone.CategoryUrl = category.CategoryUrl;
            clone.CreateDate = category.CreateDate;
            clone.DisplayOrder = category.DisplayOrder;
            //clone._isActive = category._isActive;
            //clone._isDeleted = category._isDeleted;
            //clone._isFeatured = category._isFeatured;
            //clone._isSubCategoryLoaded = category._isSubCategoryLoaded;
            //clone._parentCategory = category._parentCategory;
            //clone._parentCategoryId = category._parentCategoryId;
            //clone._productCount = category._productCount;
            //clone._subCategories = category._subCategories;
            //clone._subCategoryCount = category._subCategoryCount;
            //clone._categoryDescription = category._categoryDescription;
            //clone._productDisplayOrder = category._productDisplayOrder;
            //clone.CategoryBannerImageUrl = category._categoryBannerImageUrl;
            return clone;
        }

        #endregion

        public static Category Update(Category category, Category updatedCategory,
            bool categoryParentChanged, bool categoryNameChanged, string tempImagePath, string tempBannerImagePath)
        {
            string oldCategoryUrl = category.CategoryUrl;
            string newCategoryUrl = CategoryFileAccessUtility.GenerateNewCategoryPath(updatedCategory);
            if (categoryParentChanged && newCategoryUrl.StartsWith(oldCategoryUrl))
            {
                throw new InvalidOperationException("Cannot assign Category to specified Parent");
            }
            if (categoryParentChanged || categoryNameChanged)
            {
                //if (category.ProductCount > 0 || category.SubCategoryCount > 0)
                //   throw new InvalidOperationException("The category is not empty, so name or parent category cannot be changed");                
                //CategoryFileAccessUtility.DeleteCategoryFiles(category);
                //updatedCategory = CategoryFileAccessUtility.CreateCategoryFiles(updatedCategory, tempImagePath, tempBannerImagePath);
                try
                {
                    //CategoryFileAccessUtility.RenameCategory(oldCategoryUrl, newCategoryUrl);
                    int returnVal = CategoryDAO.UpdateTblProductCategoryUrl(oldCategoryUrl, newCategoryUrl);
                    //if (returnVal < 0)
                    //{
                    //    CategoryFileAccessUtility.RenameCategory(newCategoryUrl, oldCategoryUrl);
                    //    if (categoryNameChanged)
                    //        throw new InvalidOperationException("Failed to Rename Category");
                    //    if (categoryParentChanged)
                    //        throw new InvalidOperationException("Failed to assign Category to specified Parent");
                    //}
                }
                catch
                {
                    //if (categoryNameChanged)
                    //    throw new InvalidOperationException("Failed to Rename Category");
                    //if (categoryParentChanged)
                    //    throw new InvalidOperationException("Failed to assign Category to specified Parent");
                }
            }

            if (!string.IsNullOrEmpty(tempImagePath))
            {
                updatedCategory.CategoryImageUrl = ChangeCategoryImage(tempImagePath, updatedCategory);
            }
            if (!string.IsNullOrEmpty(tempBannerImagePath))
            {
                updatedCategory.CategoryBannerImageUrl = ChangeCategoryBannerImage(tempBannerImagePath, updatedCategory);
                CategoryFileAccessUtility.CreateTemplateFiles(updatedCategory);
            }

            CategoryDAO.Save(updatedCategory);

            return updatedCategory;
        }

        public static Category FindCategoryByName(int parentCategory, string subCategory)
        {
            subCategory = SiteUtility.BindStringInput(subCategory, SecurityLevel.Zero);
            Category categoryData = CategoryDAO.GetTblProductCategoryByName(parentCategory, subCategory);

            Category category = null;
            if (categoryData != null)
                category = categoryData;
            return category;
        }

        public static Category FindCategoryByName(string categoryName)
        {
            Category categoryData = CategoryDAO.GetTblProductCategoryByName(categoryName);
            Category category = null;
            if (categoryData != null)
                category = categoryData;
            return category;
        }

        public static ReadWriteCustomCollection<Category> PartnerCategories(int partnerId)
        {
            ReadWriteCustomCollection<Category> menuCategory = new ReadWriteCustomCollection<Category>();
            menuCategory = CategoryManager.LoadFromCustomCollection(TblPartnerCategories.GetAllTblPartnerCategoryByPartnerId(partnerId));
            return menuCategory;
        }

        /**************************************************/
        public static Category GetById(int categoryId)
        {
            if (categoryId <= 0) return null;
            return CategoryDAO.GetTblProductCategoryByCategoryId(categoryId);
        }

        public static Category GetByCategoryUrl(string categoryUrl)
        {
            return CategoryDAO.GetTblProductCategoryByUrl(categoryUrl);
        }
    }
}